home *** CD-ROM | disk | FTP | other *** search
/ American Osteopathic Ass…tion Yearbook 2005 & 2006 / American Osteopathic Association Yearbook 2005 & 2006.iso / mac / app / httpheadertypes.pyc (.txt) < prev    next >
Encoding:
Python Compiled Bytecode  |  2004-07-22  |  43.9 KB  |  888 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyc (Python 2.3)
  3.  
  4. """
  5. HTTP Header Types
  6.  
  7. This module contains the GenericHeader class, which can be (and is) 
  8. subclassed to define the behaviour of a HTTP header. The class which
  9. handles a particular header's representation is determined by the
  10. header_names dictionary.
  11.  
  12. Each of the classes has the same basic interface:
  13.  
  14. * a parse() method - which will parse the raw header payload fed to it (and
  15.   raise errors as necessary)
  16. * a data dictionary - which allows access to the raw data after parsing
  17.   (although most operations may be performed directly upon the object)
  18. * a __repr__ method  - to print the data correctly in the Header's format
  19.  
  20. If the object is instantiated with an 'instr' argument, it is parsed
  21. automatically. If it is instantiated with a 'data' argument, that value is
  22. inserted into the data dictionary.
  23.  
  24. The original header before parsing, if any, is available as the 'raw'
  25. attribute. 
  26.  
  27. Many of the headers are Lists, which are comma-seperated. Because the List
  28. class is a subclass of the UserList object, it can be accessed like a normal
  29. list. The same holds true for the Dict class, with respect to dictionaries.
  30.  
  31. Each class has a short __doc__ string that describes any special attributes
  32. or behaviours.
  33.  
  34. the get_header_name function returns the canonical capitalisation of the
  35. header name fed to it, if available, or a capitalied version if not.
  36.  
  37.  
  38. TODO
  39. - QValList - sort / get_best
  40. - Warning = list of (int str quostr quohttpdate) ; (currently List)
  41. - Expect = list of token[=qs] [;param] OR 100-continue ; (currently List)
  42. - digest authorization
  43. - Set-Cookie only takes the last one. Stupid !@#%$ Netscape spec!
  44. - Range is a pretty pitiful implementation so far.
  45. - Content-Range  ; (currently Str)
  46. """
  47. import time
  48. import re
  49. import rfc822
  50. import urlparse
  51. import base64
  52. from string import lower, join, strip, split, replace, capitalize
  53. from operator import add, sub, mul, div, neg
  54. from UserList import UserList
  55. from UserDict import UserDict
  56. __version__ = '0.61'
  57. DATA = intern('data')
  58. commapat = re.compile('\n\t(?:,\\s*|^)\n\t(\n\t(?:\n\t"(?:\\\\"|[^"])*"\t\n\t|\n\t[^,"]+\n\t)*\n\t)\n', re.VERBOSE)
  59.  
  60. def splitoncomma(instr):
  61.     if not instr:
  62.         return []
  63.     
  64.     return commapat.findall(instr)
  65.  
  66. semipat = re.compile('\n\t(?:;\\s*|^)\n\t(\n\t(?:\n\t"(?:\\\\"|[^"])*"\t\n\t|\n\t[^;"]+\n\t)*\n\t)\n', re.VERBOSE)
  67.  
  68. def splitonsemi(instr):
  69.     if not instr:
  70.         return []
  71.     
  72.     return semipat.findall(instr)
  73.  
  74.  
  75. class GenericHeader:
  76.     '''
  77. Base class for HTTP Headers. Should be subclassed.
  78. '''
  79.     
  80.     def __init__(self, instr = None):
  81.         ''' 
  82. \t\t    Initialize a header; can take:
  83. \t\t      instr - a string to be parsed
  84. \t\t      data - parsed data to be instantiated into 
  85.             only one of these should be specified.
  86. \t\t'''
  87.         self.raw = instr
  88.         self._is_foldable = 1
  89.         self._is_simple = 1
  90.         if instr is not None:
  91.             self.parse(instr)
  92.         
  93.  
  94.     
  95.     def __setattr__(self, attr, val):
  96.         """
  97. \t\t    Set an attribute.
  98. \t\t    If attr is 'data', it will be run through ._screen().
  99. \t\t\tOtherwise, can set arbitrary attributes.
  100. \t\t"""
  101.         if attr == DATA and hasattr(self, DATA):
  102.             self.__dict__[DATA] = self._screen(val)
  103.         else:
  104.             self.__dict__[attr] = val
  105.  
  106.     
  107.     def __add__(self, other):
  108.         self.__dict__[DATA] = self.data + self._screen(other)
  109.         return self
  110.  
  111.     
  112.     def __radd__(self, other):
  113.         return add(self._screen(other), self.data)
  114.  
  115.     
  116.     def __sub__(self, other):
  117.         self.__dict__[DATA] = self.data - self._screen(other)
  118.         return self
  119.  
  120.     
  121.     def __rsub__(self, other):
  122.         return sub(self._screen(other), self.data)
  123.  
  124.     
  125.     def __cmp__(self, other):
  126.         return cmp(self.data, self._screen(other))
  127.  
  128.     
  129.     def __nonzero__(self):
  130.         if self.data:
  131.             return 1
  132.         else:
  133.             return 0
  134.  
  135.     
  136.     def _screen(self, inp):
  137.         ''' Decide whether the input needs to be processed '''
  138.         if isinstance(inp, self.__class__):
  139.             return inp.data
  140.         elif type(inp) is type(self.data) and self._is_simple:
  141.             return inp
  142.         else:
  143.             return self._process(inp)
  144.  
  145.     
  146.     def _process(self, inp):
  147.         ''' 
  148. \t\t   Transform raw input into suitable header data. Should
  149. \t\t   be overridden.
  150. \t  \t'''
  151.         return inp
  152.  
  153.     
  154.     def parse(self, instr):
  155.         ''' Parse an input string into header data '''
  156.         self.__dict__[DATA] = self._screen(instr)
  157.  
  158.     
  159.     def __repr__(self):
  160.         ''' Output the data in HTTP header format. Can be overridden. '''
  161.         return str(self.data)
  162.  
  163.  
  164.  
  165. class Int(GenericHeader):
  166.     '''
  167. Integer.
  168. '''
  169.     
  170.     def __init__(self, instr = None):
  171.         self.data = 0
  172.         GenericHeader.__init__(self, instr)
  173.  
  174.     
  175.     def __mul__(self, other):
  176.         self.__dict__[DATA] = self.data * self._screen(other)
  177.         return self
  178.  
  179.     
  180.     def __rmul__(self, other):
  181.         return mul(self._process(other), self.data)
  182.  
  183.     
  184.     def __div__(self, other):
  185.         self.__dict__[DATA] = self.data / self._screen(other)
  186.         return self
  187.  
  188.     
  189.     def __rdiv__(self, other):
  190.         return div(self._process(other), self.data)
  191.  
  192.     
  193.     def __int__(self):
  194.         return int(self.data)
  195.  
  196.     
  197.     def __float__(self):
  198.         return float(self.data)
  199.  
  200.     
  201.     def __abs__(self):
  202.         return abs(self.data)
  203.  
  204.     
  205.     def __neg__(self):
  206.         return neg(self.data)
  207.  
  208.     
  209.     def _process(self, inp):
  210.         return int(inp)
  211.  
  212.  
  213.  
  214. class Str(GenericHeader):
  215.     '''
  216. String (case-sensative)
  217. '''
  218.     
  219.     def __init__(self, instr = None, case_sens = 1):
  220.         self._case_sens = case_sens
  221.         self.data = ''
  222.         GenericHeader.__init__(self, instr)
  223.  
  224.     
  225.     def __getitem__(self, i):
  226.         return self.data[i]
  227.  
  228.     
  229.     def __getslice__(self, i, j):
  230.         return self.data[i:j]
  231.  
  232.     
  233.     def _process(self, inp):
  234.         if self._case_sens:
  235.             return str(inp)
  236.         else:
  237.             return lower(inp)
  238.  
  239.  
  240.  
  241. class Str_i(Str):
  242.     '''
  243. String (case-insensitive)
  244. '''
  245.     
  246.     def __init__(self, instr = None, case_sens = 0):
  247.         Str.__init__(self, instr, case_sens)
  248.         self._is_simple = 0
  249.  
  250.  
  251.  
  252. class List(GenericHeader, UserList):
  253.     '''
  254. List of case-sensitive strings.
  255. '''
  256.     
  257.     def __init__(self, instr = None, objtype = Str):
  258.         self._objtype = objtype
  259.         self.data = []
  260.         GenericHeader.__init__(self, instr)
  261.         self._is_simple = 0
  262.  
  263.     
  264.     def __setattr__(self, key, item):
  265.         if key == DATA:
  266.             self.__dict__[DATA] = self._process(item)
  267.         else:
  268.             self.__dict__[key] = item
  269.  
  270.     
  271.     def __setslice__(self, i, j, other):
  272.         i = max(i, 0)
  273.         j = max(j, 0)
  274.         self.__dict__[data][i:j] = self._process(other)
  275.  
  276.     
  277.     def __setitem__(self, i, item):
  278.         self.__dict__[data][i] = self._objtype(item)
  279.  
  280.     
  281.     def append(self, item):
  282.         self.__dict__[DATA].append(self._objtype(item))
  283.  
  284.     
  285.     def insert(self, i, item):
  286.         self.__dict__[DATA].insert(i, self._objtype(item))
  287.  
  288.     
  289.     def _process(self, inp):
  290.         if type(inp) is type(''):
  291.             inp = map(strip, splitoncomma(inp))
  292.         
  293.         l = []
  294.         for header in inp:
  295.             if not header:
  296.                 continue
  297.             
  298.             l.append(self._objtype(header))
  299.         
  300.         return l
  301.  
  302.     
  303.     def __repr__(self):
  304.         return join(map(repr, self.data), ', ')
  305.  
  306.  
  307.  
  308. class List_i(List):
  309.     '''
  310. List of case-insensitive strings.
  311. '''
  312.     
  313.     def __init__(self, instr = None):
  314.         List.__init__(self, instr, Str_i)
  315.  
  316.  
  317.  
  318. class Dict(GenericHeader, UserDict):
  319.     '''
  320. Dictionary of key=value pairs, separated by commas. Keys are 
  321. case-insensitive; values are not. If possible, the value will be
  322. converted to an integer.
  323. '''
  324.     
  325.     def __init__(self, instr = None, splitfunc = splitoncomma, joinchar = ','):
  326.         self.data = { }
  327.         self._splitfunc = splitfunc
  328.         self._joinchar = joinchar
  329.         GenericHeader.__init__(self, instr)
  330.         self._is_simple = 0
  331.  
  332.     
  333.     def __setattr__(self, k, v):
  334.         GenericHeader.__setattr__(self, k, v)
  335.  
  336.     
  337.     def _process(self, inp):
  338.         o = self._splitfunc(inp)
  339.         res = { }
  340.         for i in o:
  341.             
  342.             try:
  343.                 (name, value) = split(strip(i), '=', 1)
  344.                 name = lower(name)
  345.                 value = unquotestring(value)
  346.                 if name in [
  347.                     'private',
  348.                     'no-cache']:
  349.                     value = map(get_header_name, self._splitfunc(value))
  350.                 
  351.                 
  352.                 try:
  353.                     value = int(value)
  354.                 except:
  355.                     pass
  356.  
  357.             except ValueError:
  358.                 (name, value) = (lower(strip(i)), None)
  359.  
  360.             res[name] = value
  361.         
  362.         return res
  363.  
  364.     
  365.     def __repr__(self):
  366.         o = []
  367.         for k, v in self.data.items():
  368.             k = lower(k)
  369.             if v == None:
  370.                 o.append(k)
  371.                 continue
  372.             if k in [
  373.                 'private',
  374.                 'no-cache'] and type(v) == type([]):
  375.                 v = '"%s"' % join(map(get_header_name, v), self._joinchar + ' ')
  376.             elif type(v) is type(''):
  377.                 v = quotestring(v)
  378.             
  379.             o.append('%s=%s' % (k, v))
  380.         
  381.         return join(o, self._joinchar + ' ')
  382.  
  383.  
  384.  
  385. class SemiDict(Dict):
  386.     
  387.     def __init__(self, instr = None):
  388.         Dict.__init__(self, instr, splitonsemi, ';')
  389.  
  390.  
  391.  
  392. class SemiDictList(List):
  393.     
  394.     def __init__(self, instr = None):
  395.         List.__init__(self, instr, SemiDict)
  396.  
  397.  
  398.  
  399. class ETag(Str):
  400.     '''
  401. ETag. The value set will be quoted (and escaped, if need be). The .weak
  402. attribute denotes a weak validator.
  403. '''
  404.     
  405.     def __init__(self, instr = None):
  406.         self.weak = 0
  407.         Str.__init__(self, instr)
  408.  
  409.     
  410.     def _process(self, inp):
  411.         self.weak = 0
  412.         if inp[:2] == 'W/':
  413.             self.weak = 1
  414.             inp = inp[2:]
  415.         
  416.         return unquotestring(inp)
  417.  
  418.     
  419.     def __repr__(self):
  420.         weak_str = ''
  421.         if self.weak:
  422.             weak_str = 'W/'
  423.         
  424.         return '%s%s' % (weak_str, quotestring(self.data, force = 1))
  425.  
  426.  
  427.  
  428. class ETagList(List):
  429.     '''
  430. List of ETags.
  431. '''
  432.     
  433.     def __init__(self, instr = None):
  434.         List.__init__(self, instr, ETag)
  435.  
  436.  
  437.  
  438. class HttpDate(Int):
  439.     '''
  440. HTTP Date - available as seconds since Epoch.
  441. '''
  442.     
  443.     def __init__(self, instr = None):
  444.         GenericHeader.__init__(self, instr)
  445.  
  446.     
  447.     def _process(self, instr):
  448.         parsed = rfc822.parsedate(instr)
  449.         
  450.         try:
  451.             return timegm(parsed)
  452.         except:
  453.             return None
  454.  
  455.  
  456.     
  457.     def __repr__(self):
  458.         
  459.         try:
  460.             return time.strftime('%a, %d %b %Y %H:%M:%S GMT', time.gmtime(self.data))
  461.         except:
  462.             return '0'
  463.  
  464.  
  465.  
  466.  
  467. class Uri(GenericHeader, UserList):
  468.     '''
  469. URI - available as urlparse 6-tuple.
  470. '''
  471.     
  472.     def __init__(self, instr = None):
  473.         self.data = ('', '', '', '', '', '')
  474.         GenericHeader.__init__(self, instr)
  475.  
  476.     
  477.     def _process(self, instr):
  478.         return urlparse.urlparse(instr)
  479.  
  480.     
  481.     def __repr__(self):
  482.         return urlparse.urlunparse(self.data)
  483.  
  484.  
  485.  
  486. class Param(Str_i):
  487.     '''
  488. Parameterized data. primary data available as object instance, 
  489. parameters available as a dictionary in the .params attribute.
  490. Param keys are case-insensitive, values are case-sensitive.
  491. '''
  492.     
  493.     def __init__(self, instr = None):
  494.         self.params = { }
  495.         Str_i.__init__(self, instr)
  496.         self._is_simple = 0
  497.  
  498.     
  499.     def _process(self, inp):
  500.         self.params = { }
  501.         
  502.         try:
  503.             (data, args) = split(inp, ';', 1)
  504.         except ValueError:
  505.             return inp
  506.  
  507.         for param in splitonsemi(args):
  508.             
  509.             try:
  510.                 (attr, value) = split(param, '=', 1)
  511.                 self.params[lower(attr)] = unquotestring(value)
  512.             continue
  513.             except ValueError:
  514.                 self.params[lower(param)] = None
  515.                 continue
  516.             
  517.  
  518.         
  519.         return data
  520.  
  521.     
  522.     def __repr__(self):
  523.         (o, out) = ([], '')
  524.         for k, v in self.params.items():
  525.             if v == None:
  526.                 o.append(k)
  527.                 continue
  528.             o.append('%s=%s' % (k, quotestring(v)))
  529.         
  530.         if o:
  531.             out = '; ' + join(o, '; ')
  532.         
  533.         return '%s%s' % (self.data, out)
  534.  
  535.  
  536.  
  537. class ParamList(List):
  538.     
  539.     def __init__(self, instr = None):
  540.         List.__init__(self, instr, Param)
  541.  
  542.  
  543.  
  544. class QValList(ParamList):
  545.     """
  546. List of parameterised data. If an item has a 'q' parameter associated with 
  547. it, that will determine its relative value.
  548. """
  549.     
  550.     def __init__(self, instr = None):
  551.         ParamList.__init__(self, instr)
  552.  
  553.  
  554.  
  555. class Header(Str):
  556.     '''
  557. Canonicalized HTTP header name.
  558. '''
  559.     
  560.     def __init__(self, instr = None):
  561.         Str.__init__(self, instr)
  562.         self._is_simple = 0
  563.  
  564.     
  565.     def _process(self, inp):
  566.         return get_header_name(inp)
  567.  
  568.  
  569.  
  570. class HeaderList(List):
  571.     '''
  572. List of HTTP headers in canonical format.
  573. '''
  574.     
  575.     def __init__(self, instr = None):
  576.         List.__init__(self, instr, Header)
  577.  
  578.  
  579.  
  580. class Challenge(Dict):
  581.     """
  582. HTTP Authorization challenge. Currently, only Basic is supported.
  583. Attributes:
  584.   .scheme : scheme used (should be set to 'basic')
  585.   .realm : authentication realm
  586. """
  587.     
  588.     def __init__(self, instr = None):
  589.         Dict.__init__(self, instr)
  590.  
  591.     
  592.     def _process(self, inp):
  593.         
  594.         try:
  595.             (scheme, args) = split(inp, None, 1)
  596.         except:
  597.             (scheme, args) = (inp, None)
  598.  
  599.         self.data['scheme'] = lower(scheme)
  600.         return Dict._process(self, args)
  601.  
  602.     
  603.     def __repr__(self):
  604.         if lower(self.data['scheme']) == 'basic':
  605.             o = []
  606.             for k, v in self.data.items():
  607.                 if lower(k) == 'scheme':
  608.                     continue
  609.                 
  610.                 o.append('%s=%s' % (k, quotestring(v)))
  611.             
  612.             return '%s %s' % (capitalize(lower(self.data['scheme'])), join(o, ', '))
  613.         else:
  614.             raise StandardError, 'Digest Auth not supported yet.'
  615.  
  616.  
  617.  
  618. class Credentials(Dict):
  619.     """
  620. HTTP Authorization credentials. Currently, only Basic is supported.
  621. Attributes:
  622.   .scheme : scheme used (should be set to 'basic')
  623.   .username : username
  624.   .password : password
  625. """
  626.     
  627.     def __init__(self, instr = None):
  628.         Dict.__init__(self, instr)
  629.  
  630.     
  631.     def _process(self, inp):
  632.         (scheme, args) = split(inp, None, 1)
  633.         self.data['scheme'] = lower(scheme)
  634.         if self.data['scheme'] == 'basic':
  635.             (self.data['username'], self.data['password']) = split(base64.decodestring(args), ':', 1)
  636.         else:
  637.             raise StandardError, 'Digest Auth not supported yet.'
  638.         return None
  639.  
  640.     
  641.     def __repr__(self):
  642.         if lower(self.data['scheme']) == 'basic':
  643.             return '%s %s' % (capitalize(lower(self.data['scheme'])), base64.encodestring(join((self.data['username'], self.data['password']), ':'))[:-1])
  644.         else:
  645.             raise StandardError, 'Digest Auth not supported yet.'
  646.  
  647.  
  648.  
  649. class Range(List):
  650.     """
  651. Range request. Specifier is available on .specifier attribute (should be
  652. 'bytes'); ranges are in the List itself.
  653. """
  654.     
  655.     def __init__(self, instr = None):
  656.         self.specifier = 'bytes'
  657.         List.__init__(self, instr, Str)
  658.  
  659.     
  660.     def _process(self, inp):
  661.         (specifier, args) = split(inp, '=', 1)
  662.         self.specifier = lower(specifier)
  663.         return List._process(self, args)
  664.  
  665.     
  666.     def __repr__(self):
  667.         return '%s=%s' % (self.specifier, List.__repr__(self))
  668.  
  669.  
  670.  
  671. class HttpDateorInt(HttpDate, Int):
  672.     '''
  673. Either a HTTP Date or Integer. If a date is represented as seconds since
  674. the epoch, the .is_date attribute should be true; if it represents delta
  675. seconds, it should be false.
  676. '''
  677.     
  678.     def __init__(self, instr = None):
  679.         self.is_date = 0
  680.         HttpDate.__init__(self, instr)
  681.         self._is_simple = 0
  682.  
  683.     
  684.     def _process(self, inp):
  685.         
  686.         try:
  687.             return Int._process(self, inp)
  688.         except:
  689.             self.is_date = 1
  690.             return HttpDate._process(self, inp)
  691.  
  692.  
  693.     
  694.     def __repr__(self):
  695.         if self.is_date:
  696.             return HttpDate.__repr__(self)
  697.         else:
  698.             return Int.__repr__(self)
  699.  
  700.  
  701.  
  702. class Validator(HttpDate, ETag):
  703.     '''
  704. Either a HTTP Date or an ETag. If a date is represented, the .is_date
  705. attribute should be true; otherwise, it should be false.
  706. '''
  707.     
  708.     def __init__(self, instr = None):
  709.         self.is_date = 0
  710.         self.weak = 0
  711.         HttpDate.__init__(self, instr)
  712.  
  713.     
  714.     def _process(self, inp):
  715.         self.is_date = 1
  716.         
  717.         try:
  718.             return HttpDate._process(self, inp)
  719.         except:
  720.             self.is_date = 0
  721.             self.__dict__[DATA] = ''
  722.             return ETag._process(self, inp)
  723.  
  724.  
  725.     
  726.     def __repr__(self):
  727.         if self.is_date:
  728.             return HttpDate.__repr__(self)
  729.         else:
  730.             return ETag.__repr__(self)
  731.  
  732.  
  733.  
  734. class SetCookie(SemiDictList):
  735.     """
  736. A SemiDictList that's not foldable, because of the !@#$ cookie spec.
  737. """
  738.     
  739.     def __init__(self, instr = None):
  740.         SemiDictList.__init__(self, instr)
  741.         self._is_foldable = 0
  742.  
  743.  
  744.  
  745. class UnknownHeader(Str):
  746.     """
  747. Generic holder for unknown headers; treats them as strings, and doesn't
  748. fold them.
  749. """
  750.     
  751.     def __init__(self, instr = None):
  752.         Str.__init__(self, instr)
  753.  
  754.  
  755. header_names = {
  756.     'Accept': QValList,
  757.     'Accept-Charset': QValList,
  758.     'Accept-Encoding': QValList,
  759.     'Accept-Language': QValList,
  760.     'Accept-Ranges': List_i,
  761.     'Age': Int,
  762.     'Allow': List,
  763.     'Authorization': Credentials,
  764.     'Cache-Control': Dict,
  765.     'Connection': List_i,
  766.     'Content-Encoding': List_i,
  767.     'Content-Language': List_i,
  768.     'Content-Length': Int,
  769.     'Content-Location': Uri,
  770.     'Content-MD5': Str,
  771.     'Content-Range': Str,
  772.     'Content-Type': Param,
  773.     'Cookie': Dict,
  774.     'Date': HttpDate,
  775.     'ETag': ETag,
  776.     'Expect': List,
  777.     'Expires': HttpDate,
  778.     'From': Str,
  779.     'Host': Str_i,
  780.     'If-Match': ETagList,
  781.     'If-Modified-Since': HttpDate,
  782.     'If-None-Match': ETagList,
  783.     'Last-Modified': HttpDate,
  784.     'Location': Uri,
  785.     'Max-Forwards': Int,
  786.     'Pragma': Dict,
  787.     'Proxy-Authenticate': Challenge,
  788.     'Proxy-Authorization': Credentials,
  789.     'Range': Range,
  790.     'Referer': Uri,
  791.     'Retry-After': HttpDateorInt,
  792.     'Server': Str,
  793.     'Set-Cookie': SetCookie,
  794.     'Set-Cookie2': SemiDictList,
  795.     'TE': QValList,
  796.     'Trailer': HeaderList,
  797.     'Transfer-Encoding': List_i,
  798.     'Upgrade': List,
  799.     'User-Agent': Str,
  800.     'Vary': HeaderList,
  801.     'Via': List,
  802.     'Warning': List,
  803.     'WWW-Authenticate': Challenge }
  804. header_name_cache = { }
  805. header_name_cache_size = 1000
  806. header_name_list = map(intern, header_names.keys())
  807. header_name_lower_list = map(lower, header_name_list)
  808.  
  809. def get_header_name(query):
  810.     '''
  811. \tGiven a header in any case, return its properly capitalised version.
  812. \t'''
  813.     global header_name_cache
  814.     if not header_name_cache.has_key(query):
  815.         if len(header_name_cache) > header_name_cache_size:
  816.             header_name_cache = { }
  817.         
  818.         
  819.         try:
  820.             header_name_cache[query] = header_name_list[header_name_lower_list.index(lower(query))]
  821.         except (KeyError, ValueError):
  822.             header_name_cache[query] = capitalize(lower(query))
  823.         except:
  824.             None<EXCEPTION MATCH>(KeyError, ValueError)
  825.         
  826.  
  827.     None<EXCEPTION MATCH>(KeyError, ValueError)
  828.     return header_name_cache[query]
  829.  
  830.  
  831. def timegm(tmtuple):
  832.     ''' returns epoch seconds from a GMT time tuple. '''
  833.     import calendar
  834.     EPOCH = 1970
  835.     (year, month, day, hour, minute, second) = tmtuple[:6]
  836.     if year < EPOCH:
  837.         if year < 69:
  838.             year = year + 2000
  839.         else:
  840.             year = year + 1900
  841.         if year < EPOCH:
  842.             raise ValueError, 'invalid year'
  843.         
  844.     
  845.     if not None if month <= month else month <= 12:
  846.         raise TypeError, 'invalid month'
  847.     
  848.     days = 365 * (year - EPOCH) + calendar.leapdays(EPOCH, year)
  849.     for i in range(1, month):
  850.         days = days + calendar.mdays[i]
  851.     
  852.     if month > 2 and calendar.isleap(year):
  853.         days = days + 1
  854.     
  855.     days = days + day - 1
  856.     hours = days * 24 + hour
  857.     minutes = hours * 60 + minute
  858.     seconds = minutes * 60 + second
  859.     return seconds
  860.  
  861.  
  862. def quotestring(instr, force = 0):
  863.     ''' does NOT quote control characters. '''
  864.     if not force and '"' not in instr and ',' not in instr and '\\' not in instr and ';' not in instr:
  865.         return instr
  866.     
  867.     if instr == '*':
  868.         return instr
  869.     
  870.     instr = re.sub('\\\\', '\\\\\\\\', instr)
  871.     return '"%s"' % re.sub('"', '\\\\"', instr)
  872.  
  873.  
  874. def unquotestring(instr):
  875.     ''' does NOT unquote control characters. '''
  876.     instr = strip(instr)
  877.     if not instr or instr == '*':
  878.         return instr
  879.     
  880.     if instr[-1] == instr[-1]:
  881.         pass
  882.     elif instr[-1] == '"':
  883.         instr = instr[1:-1]
  884.         instr = re.sub('\\\\(.)', '\\1', instr)
  885.     
  886.     return instr
  887.  
  888.